package datastorage

import (
	"MqttCloudProtocolServer/publiclib/datamodel/dborm"
	"MqttCloudProtocolServer/publiclib/datamodel/redismodel"
	"MqttCloudProtocolServer/publiclib/dbcontrol"
	"context"
	"encoding/json"
	"errors"
	"strconv"
	"strings"
	"sync"

	"github.com/redis/go-redis/v9"
	"github.com/wonderivan/logger"
)

type RedisStorage struct {
	callbackIndex map[string]func(tag string, value float64) bool
	rwLocker      *sync.RWMutex
	realdbcfg     *dborm.Savedbconf
	redisClient   *redis.Client
	subchan       *redis.PubSub
}

type WriteJson struct {
	Tag  string  `json:"tag"`
	Data float64 `json:"data"`
}

var storageContent *RedisStorage
var syncLocker = new(sync.Mutex)

const subTopic = "0000_tag_write_channel"

func GetRedisStorageContent() *RedisStorage {
	syncLocker.Lock()
	defer syncLocker.Unlock()
	if storageContent == nil {
		storageContent = new(RedisStorage)
		storageContent.callbackIndex = make(map[string]func(tag string, value float64) bool)
		storageContent.rwLocker = new(sync.RWMutex)
		savedbConfControl := dbcontrol.CreateSavedbConfControl()
		if savedbConfControl == nil {
			return nil
		}
		if err := savedbConfControl.FindByID("redisReal"); err != nil {
			return nil
		}
		if savedbConfControl.Data == nil {
			return nil
		}
		storageContent.realdbcfg = savedbConfControl.Data
		dbNum, err := strconv.Atoi(storageContent.realdbcfg.Dbname)
		if err != nil {
			return nil
		}
		option := &redis.Options{
			Addr:     storageContent.realdbcfg.Host + ":" + strconv.Itoa(storageContent.realdbcfg.Port), // redis地址
			Password: storageContent.realdbcfg.Password,                                                 // 密码
			DB:       dbNum,                                                                             // 使用数据库
		}
		if len(strings.TrimSpace(storageContent.realdbcfg.UserName)) > 0 {
			option.Username = storageContent.realdbcfg.UserName
		}
		storageContent.redisClient = redis.NewClient(option)
		go storageContent.Subscribe(subTopic)
	}
	return storageContent
}
func (_this *RedisStorage) Subscribe(topic string) {
	if _this.redisClient != nil {
		ctx := context.Background()
		_this.subchan = _this.redisClient.PSubscribe(ctx, topic)
		for msg := range _this.subchan.Channel() {
			logger.Debug("channel=%s message=%s\n", msg.Channel, msg.Payload)
			if len(strings.TrimSpace(msg.Payload)) != 0 {
				obj := new(WriteJson)
				if err := json.Unmarshal([]byte(msg.Payload), obj); err != nil {
					logger.Info(err)
					_this.redisClient.Publish(ctx, "0001_tag_write_channel", "error:写命令出错")
				} else {
					if err := _this.WriteData(obj.Tag, obj.Data); err == nil {
						logger.Info(errors.New("success"))
						_this.redisClient.Publish(ctx, "0001_tag_write_channel", "success")
					} else {
						logger.Info(errors.New("fault:" + err.Error()))
						_this.redisClient.Publish(ctx, "0001_tag_write_channel", "fault:"+err.Error())
					}
				}
			} else {
				logger.Info(errors.New("error:无控制对象信息"))
				_this.redisClient.Publish(ctx, "0001_tag_write_channel", "error:无控制对象信息")
			}
		}
	} else {
		logger.Alert("Redis 无法订阅:Redis客户端为空")
	}
}

// 注册回调函数
func (_this *RedisStorage) RegistCallback(key string, callback func(tag string, value float64) bool) error {
	if _this.callbackIndex == nil || _this.rwLocker == nil {
		return errors.New("初始化未完成")
	}
	_this.rwLocker.Lock()
	_this.callbackIndex[key] = callback
	_this.rwLocker.Unlock()
	return nil
}

// 注销回调函数
func (_this *RedisStorage) UnRegistCallback(key string) error {
	if _this.callbackIndex == nil || _this.rwLocker == nil {
		return errors.New("初始化未完成")
	}
	_this.rwLocker.Lock()
	delete(_this.callbackIndex, key)
	_this.rwLocker.Unlock()
	return nil
}

// 保存到redis
func (_this *RedisStorage) SaveToRedis(tabName string, data *redismodel.RealData) error {
	//logger.Debug("tabName:%s, Key:%s, Value:%s, ValueDis:%s, LastTime:%s", tabName, data.Key, data.Value, data.ValueDis, data.LastTime)
	if tabName == "realData" {
		tempData := make(map[string]interface{})
		tempData["Value"] = data.Value
		tempData["ValueDis"] = data.ValueDis
		tempData["DateTime"] = data.LastTime
		tempData["LastTime"] = data.LastTime.Format("2006-01-02 15:04:05.000")
		ctx := context.Background()
		err := _this.redisClient.HMSet(ctx, data.Key, tempData).Err()
		if err != nil {
			logger.Alert("redis set %s error:%s", data.Key+".Value", err)
			return err
		}
	}
	return nil
}

// 从redis加载
func (_this *RedisStorage) LoadFromRedis(tabName, key string) (interface{}, error) {
	return nil, nil
}

func (_this *RedisStorage) WriteData(tag string, value float64) error {
	if _this.callbackIndex == nil || _this.rwLocker == nil {
		return errors.New("初始化未完成")
	}
	_this.rwLocker.RLock()
	callback, ok := _this.callbackIndex[tag]
	_this.rwLocker.RUnlock()
	if !ok {
		return errors.New("无法找到回调函数")
	}
	if callback(tag, value) {
		return nil
	} else {
		return errors.New("控制失败")
	}
}

func (_this *RedisStorage) Close() {
	ctx := context.Background()
	_this.subchan.Unsubscribe(ctx, subTopic)
	_this.subchan.Close()
	_this.redisClient.Close()
}
